﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using PmSoft.Core;
using PmSoft.Web.Abstractions.ErrorCode;
using System.Text;
using System.Text.RegularExpressions;

namespace PmSoft.Web.Abstractions.Middlewares;

// 中间件类：过滤XSS攻击，同时允许合法HTML
public class XssFilterMiddleware
{
	private readonly RequestDelegate _next;

	public XssFilterMiddleware(RequestDelegate next)
	{
		_next = next;
	}

	public async Task InvokeAsync(HttpContext context)
	{
		// 检查请求是否需要过滤
		if (context.Request.Method == "POST" || context.Request.Method == "PUT" || context.Request.QueryString.HasValue)
		{
			// 检查查询字符串
			if (ContainsDangerousXss(context.Request.QueryString.ToString()))
			{
				await ReturnBadRequest(context, "查询字符串中检测到危险的XSS攻击");
				return;
			}

			// 检查表单数据
			if (context.Request.HasFormContentType)
			{
				var form = await context.Request.ReadFormAsync();
				if (form != null)
				{
					foreach (var key in form.Keys)
					{
						if (ContainsDangerousXss(form[key]))
						{
							await ReturnBadRequest(context, "表单数据中检测到危险的XSS攻击");
							return;
						}
					}
				}
			}
			// 检查JSON请求体
			else if (context.Request.ContentType?.Contains("application/json") == true)
			{
				context.Request.EnableBuffering();
				using var reader = new StreamReader(context.Request.Body, Encoding.UTF8, leaveOpen: true);
				string body = await reader.ReadToEndAsync();
				if (ContainsDangerousXss(body))
				{
					await ReturnBadRequest(context, "JSON数据中检测到危险的XSS攻击");
					return;
				}
				context.Request.Body.Position = 0;
			}
		}

		// 继续处理请求
		await _next(context);
	}

	// 检查是否包含危险的XSS攻击（允许普通HTML，但禁止恶意脚本）
	private static bool ContainsDangerousXss(string? input)
	{
		if (string.IsNullOrEmpty(input))
			return false;

		// 定义危险的XSS模式，允许普通HTML标签但禁止脚本和事件
		string[] dangerousPatterns = new[]
		{
				@"<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>", // script标签
                @"javascript:", // javascript伪协议
                @"on\w+\s*=", // 事件属性，如onload, onclick
                @"<iframe\b[^>]*\bsrc\s*=", // iframe带src属性
                @"<img\b[^>]*\bon\w+\s*=", // img标签中的事件
                @"expression\(", // IE中的CSS表达式
                @"<object\b", // object标签
                @"<embed\b", // embed标签
                @"<link\b[^>]*\bhref\s*=", // link标签带href
                @"eval\s*\(", // eval函数
                @"document\.cookie" // 操作cookie的脚本
            };

		return dangerousPatterns.Any(pattern => Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase));
	}

	// 返回400 Bad Request响应
	private static async Task ReturnBadRequest(HttpContext context, string message)
	{
		context.Response.StatusCode = ErrorCodeManager.GetError("XSSATACK").HttpStatus;
		context.Response.ContentType = "application/json";
		await context.Response.WriteAsync(Json.Stringify(ApiResult.Error("XSSATACK", message)));
	}
}

// 扩展方法
public static class XssFilterMiddlewareExtensions
{
	public static IApplicationBuilder UseXssFilter(this IApplicationBuilder builder)
	{
		return builder.UseMiddleware<XssFilterMiddleware>();
	}
}
